package com.hy.mvc.biz.utils;

import org.apache.commons.lang3.ArrayUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author Booker
 * @version 1.2.20
 * @func 日期格式化、计算辅助工具
 * @date 2017-12-12
 */
public class DateUtils {

    public static final String YMD = "yyyy-MM-dd";

    public static final String MD = "MM-dd";

    public static final String YMDHms = "yyyy-MM-dd HH:mm:ss";

    public static final String Hms = "HH:mm:ss";

    public static final String Hm = "HH:mm";

    public static final byte SECOND = 0;

    public static final byte MINUTE = 1;

    public static final byte HOUR = 2;

    public static final byte DAY = 3;

    private static final int NUMBER_OF_ONE_WEEK = 7;

    private final static int MAX_DATE_RANGE = 365;

    private final static int VALID_DATE_RANGE_OF_180 = 180;

    /**
     * @func 把date字符串转化为指定pattern的Date，默认pattern为yyyy-MM-dd
     * @date 2013-5-28
     * @version 1.2.20
     */
    public static Date parse4y2M2d(String dateStr) {
        return parse(dateStr, YMD);
    }


    /**
     * @func 把date转化为指定pattern的字符串，默认pattern为yyyy-MM-dd
     * @auth moxiao.hd
     * @date 2013-5-28
     * @version 1.2.20
     */
    public static Date formatDate(Date date, String pattern) {
        String dateString = format(date, pattern);
        Date newDate = parse(dateString, pattern);
        return newDate;
    }

    /**
     * @func 把date转化为指定pattern的字符串，默认pattern为yyyy-MM-dd
     * @auth moxiao.hd
     * @date 2013-5-28
     * @version 1.2.20
     */
    public static String format(Date date) {
        return format(date, YMD);
    }

    /**
     * @func 把date转化为指定pattern的字符串
     * @auth moxiao.hd
     * @date 2013-5-28
     * @version 1.2.20
     */
    public static String format(Date date, String pattern) {
        if (date == null) {
            return null;
        }

        if (pattern == null || pattern.isEmpty()) {
            pattern = YMD;
        }

        DateFormat df = new SimpleDateFormat(pattern);
        return df.format(date);

    }

    /**
     * @func 把date字符串转化为指定pattern的Date，默认pattern为yyyy-MM-dd
     * @auth moxiao.hd
     * @date 2013-5-28
     * @version 1.2.20
     */
    public static Date parse(String dateStr) {
        return parse(dateStr, YMD);
    }

    /**
     * @func 把date字符串转化为指定pattern的Date
     * @auth moxiao.hd
     * @date 2013-5-28
     * @version 1.2.20
     */
    public static Date parse(String dateStr, String pattern) {
        if (dateStr == null || dateStr.isEmpty()) {
            return null;
        }

        if (pattern == null || pattern.isEmpty()) {
            pattern = YMD;
        }

        DateFormat df = new SimpleDateFormat(pattern);

        try {
            Date date = df.parse(dateStr);
            return date;
        } catch (Exception e) {
            return null;
        }

    }

    /**
     * @func 把date字符串转化为指定pattern的Date，默认pattern为yyyy-MM-dd
     * @auth moxiao.hd
     * @date 2013-5-28
     * @version 1.2.20
     */
    public static Date parse2(String dateStr) throws ParseException {
        return parse2(dateStr, YMD);
    }

    /**
     * @func 把date字符串转化为指定pattern的Date
     * @auth moxiao.hd
     * @date 2013-5-28
     * @version 1.2.20
     */
    public static Date parse2(String dateStr, String pattern) throws ParseException {
        if (dateStr == null || dateStr.isEmpty()) {
            return null;
        }

        if (pattern == null || pattern.isEmpty()) {
            pattern = YMD;
        }

        DateFormat df = new SimpleDateFormat(pattern);

        Date date = df.parse(dateStr);
        return date;
    }

    /**
     * @func 判断一个日期是否是合法的日期<br>
     * strict如果为true表示2012-10-32这种日期将是错误的<br>
     * strict如果为false表示2012-10-32这种日期将视为2012-11-01，是正确的
     * @auth moxiao.hd
     * @date 2013-5-28
     * @version 1.2.20
     */
    public static boolean isValid(String date, String pattern, boolean strict) {
        if (date == null || date.isEmpty()) {
            return false;
        }

        if (pattern == null || pattern.isEmpty()) {
            pattern = YMD;
        }

        DateFormat df = new SimpleDateFormat(pattern);
        try {
            Date dateObj = df.parse(date);
            return !strict || df.format(dateObj).equals(date);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * @func 在date上增加days天
     * @auth moxiao.hd
     * @date 2013-5-28
     * @version 1.2.20
     */
    public static Date addDays(Date date, int days) {
        return org.apache.commons.lang3.time.DateUtils.addDays(date, days);
    }

    public static Date addMinutes(Date date, int mins) {
        return org.apache.commons.lang3.time.DateUtils.addMinutes(date, mins);
    }

    /**
     * @func 获得两个时间的时间差（秒）
     * @auth moxiao.hd
     * @date 2013-5-29
     * @version 1.2.20
     */
    public static int getIntervalSecond(Date from, Date to) {
        return getInterval(from, to, SECOND);
    }

    /**
     * @func 获得两个时间的时间差（分）
     * @auth moxiao.hd
     * @date 2013-5-29
     * @version 1.2.20
     */
    public static int getIntervalMinute(Date from, Date to) {
        return getInterval(from, to, MINUTE);
    }

    /**
     * @func 获得两个时间的时间差（时）
     * @auth moxiao.hd
     * @date 2013-5-29
     * @version 1.2.20
     */
    public static int getIntervalHour(Date from, Date to) {
        return getInterval(from, to, HOUR);
    }

    /**
     * @func 获得两个时间的时间差，type为时间差的类型：秒、分、时、天等
     * @auth moxiao.hd
     * @date 2013-5-29
     * @version 1.2.20
     */
    public static int getInterval(Date from, Date to, byte type) {
        if (from == null || to == null) {
            return Integer.MIN_VALUE;
        }

        long interval = to.getTime() - from.getTime();
        switch (type) {
            case SECOND:
                return (int) (interval / 1000);
            case MINUTE:
                return (int) (interval / 60000);
            case HOUR:
                return (int) (interval / 3600000);
            case DAY:
                return (int) (interval / (3600000 * 24));
            default:
                return Integer.MIN_VALUE;
        }
    }


    /**
     * @func 去掉date的时分秒（时分秒置为00:00:00）
     * @date 2013年10月28日
     * @version 1.0.0
     */
    public static Date trimTime(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 生成一天最早的时间
     *
     * @param date
     * @return
     */
    public static Date getEarliestTime(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        return c.getTime();
    }

    /**
     * 生成一天最晚的时间
     *
     * @param date
     * @return
     */
    public static Date getLatestTime(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        return c.getTime();
    }

    /**
     * 取指定日期是星期几 星期一为1,.... 星期六是6, 星期天是7
     * 这与JDK标准不同
     *
     * @param date
     * @return
     */
    public static int getDayOfWeek(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int weekday = c.get(Calendar.DAY_OF_WEEK);
        if (weekday == 1) {
            return 7;
        } else {
            return weekday - 1;
        }
    }


    /**
     * 设定指定日期的 时，分，秒
     *
     * @param date
     * @param hour
     * @param minute
     * @param secdond
     * @return
     */
    public static Date setHourMinuteSecond(Date date, int hour, int minute, int secdond) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);

        if (hour >= 0) {
            c.set(Calendar.HOUR_OF_DAY, hour);
        }

        if (minute >= 0) {
            c.set(Calendar.MINUTE, minute);
        }

        if (secdond >= 0) {
            c.set(Calendar.SECOND, secdond);
        }

        return c.getTime();
    }

    /**
     * 设定指定日期的 时，分，秒
     *
     * @return
     */
    public static Date getCurrentDate() {
        return new Date();
    }

    /**
     * 设定指定日期的 不含有时，分，秒
     *
     * @return
     */
    public static Date getCurrentDate2() {
        return trimTime(new Date());
    }

    /**
     * 获取当前日期所在的年份
     *
     * @return
     */
    public static int getCurrentYear() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.YEAR);
    }

    /**
     * 把毫秒转化成日期
     *
     * @param dateFormat(日期格式，例如：MM/ dd/yyyy HH:mm:ss)
     * @param millSec(毫秒数)
     * @return
     */
    public static Date transferLongToDate(String dateFormat, Long millSec) {
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        Date date = new Date(millSec);
        return formatDate(date, dateFormat);
    }

    /**
     * 把毫秒转化成日期
     *
     * @param dateFormat(日期格式，例如：MM/ dd/yyyy HH:mm:ss)
     * @param millSec(毫秒数)
     * @return
     */
    public static String transferLongToString(String dateFormat, Long millSec) {
        Date date = new Date(millSec);
        return format(date, dateFormat);
    }

    /**
     * 计算在开始 结束时间范围内， 在指定星期内的日期
     *
     * @param startDate
     * @param endDate
     * @param weekMarks
     * @return
     */
    public static List<Date> calculateDateRange(Date startDate, Date endDate, String[] weekMarks) {
        List<Date> dateList = new ArrayList<Date>();

        if (ArrayUtils.isEmpty(weekMarks)) {
            return dateList;
        }

        //结束日期不能早于开始日期
        if (DateUtils.getInterval(startDate, endDate, DateUtils.DAY) < 0) {
            return dateList;
        }

        //开始日期不能早于今天
        Date today = DateUtils.trimTime(new Date());
        if (DateUtils.getInterval(today, startDate, DateUtils.DAY) < 0) {
            startDate = today;
        }

        //加限制，一周的下标的个数只能 <= 7
        List<String> weekIndexs = Arrays.asList(weekMarks);
        if (weekIndexs.size() > NUMBER_OF_ONE_WEEK) {
            return dateList;
        }

        //获取起始 结束的间隔天数  包括结束日期  <=
        int dateNumber = DateUtils.getInterval(startDate, endDate, DateUtils.DAY);
        for (int i = 0; i <= dateNumber; i++) {
            Date nextDate = DateUtils.addDays(startDate, i);
            int weekIdx = DateUtils.getDayOfWeek(nextDate);
            //检查该日期是否在指定的星期内
            if (weekIndexs.contains(String.valueOf(weekIdx))) {
                dateList.add(nextDate);
            }
        }
        return dateList;
    }

    /**
     * 计算在开始 结束时间范围内， 在指定星期内的日期
     *
     * @param startDate
     * @param endDate
     * @param weekMarks
     * @return
     */
    public static List<Date> calculateDateRange2(Date startDate, Date endDate, String[] weekMarks) {
        List<Date> dateList = new ArrayList<Date>();

        if (ArrayUtils.isEmpty(weekMarks)) {
            return dateList;
        }

        //结束日期不能早于开始日期
        if (DateUtils.getInterval(startDate, endDate, DateUtils.DAY) < 0) {
            return dateList;
        }

    /*    //开始日期不能早于今天
        Date today = DateUtils.trimTime(new Date());
        if (DateUtils.getInterval(today, startDate, DateUtils.DAY) < 0) {
            startDate = today;
        }*/

        //加限制，一周的下标的个数只能 <= 7
        List<String> weekIndexs = Arrays.asList(weekMarks);
        if (weekIndexs.size() > NUMBER_OF_ONE_WEEK) {
            return dateList;
        }

        //获取起始 结束的间隔天数  包括结束日期  <=
        int dateNumber = DateUtils.getInterval(startDate, endDate, DateUtils.DAY);
        for (int i = 0; i <= dateNumber; i++) {
            Date nextDate = DateUtils.addDays(startDate, i);
            int weekIdx = DateUtils.getDayOfWeek(nextDate);
            //检查该日期是否在指定的星期内
            if (weekIndexs.contains(String.valueOf(weekIdx))) {
                dateList.add(nextDate);
            }
        }
        return dateList;
    }
    /**
     * 根据初始日期和星期下标, 来计算第一天
     *
     * @param fromDateStr
     * @param weekArray
     * @return
     */
    public static Date calculateFirstCompareDate(String fromDateStr, String[] weekArray) {
        Date fromdate = DateUtils.parse(fromDateStr);
        Date meetDate = fromdate;

        if (null != weekArray && weekArray.length > 0) {
            String firstWeekIdx = weekArray[0];
            for (int i = 0; i < 7; i++) {
                Date calDate = DateUtils.addDays(fromdate, i);
                int weekIdxOfCalDate = DateUtils.getDayOfWeek(calDate);
                if (String.valueOf(weekIdxOfCalDate).equals(firstWeekIdx)) {
                    meetDate = calDate;
                }
            }
        }

        return meetDate;
    }

    /**
     * 检查日历
     *
     * @param fromDateStr
     * @param endDateStr
     * @return
     */
    public static String checkCalendarDate(String fromDateStr, String endDateStr) {
        String errorMsg = "";
        if (DateUtils.isValid(fromDateStr, YMD, true) &&
                DateUtils.isValid(endDateStr, YMD, true)) {
            Date fromDay = DateUtils.parse(fromDateStr);
            Date endDay = DateUtils.parse(endDateStr);
            int intervalDay = DateUtils.getInterval(fromDay, endDay, DateUtils.DAY);
            if (intervalDay < 0) {
                errorMsg = "开始日期必须早于结束日期";
            }

            Date today = DateUtils.trimTime(new Date());

            int intervalDayFrom = DateUtils.getInterval(today, fromDay, DateUtils.DAY);
            if (intervalDayFrom < 0) {
                errorMsg = "开始日期必须晚于今天";
            }

            int intervalDayEnd = DateUtils.getInterval(today, endDay, DateUtils.DAY);
            if (intervalDayEnd < 0) {
                errorMsg = "结束日期必须晚于今天";
            }

            int intervalDayFromEnd = -intervalDay;
            if (intervalDayFromEnd > MAX_DATE_RANGE) {
                errorMsg = "开始日期, 结束日期不能超过一年";
            }

            // 开始日期和当前日期比较
//			Date currentDate = DateUtils.trimTime(new Date());
//			int fromLength = DateUtils.getInterval(currentDate, fromDay,
//				DateUtils.DAY);
//			if (fromLength >= VALID_DATE_RANGE_OF_180) {
//				errorMsg = "开始日期不能晚于今天180天";
//			}
//
//			// 结束日期和当前日期比较
//			int endLength = DateUtils.getInterval(currentDate, endDay,
//				DateUtils.DAY);
//			if (endLength >= VALID_DATE_RANGE_OF_180) {
//				errorMsg = "结束日期不能晚于今天180天";
//			}
        }
        return errorMsg;
    }


}
